package com.java.simple.study.juc.p5;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicIntegerArray;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * @author zhoujunlin
 * @date 2022年07月03日 21:00
 * @desc
 */
public class AtomicArraryTest {

    public static void main(String[] args) {
        /*demo(
                () -> new int[10],
                (array) -> array.length,
                (array, index) -> array[index]++,
                array -> System.out.println(Arrays.toString(array))
        );*/
        //[9635, 9592, 9558, 9555, 9562, 9569, 9631, 9561, 9566, 9577]

        demo(
                () -> new AtomicIntegerArray(10),
                AtomicIntegerArray::length,
                AtomicIntegerArray::incrementAndGet,
                System.out::println
        );
        // [10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000]
    }


    /**
     * 测试安全/非安全数组
     *
     * @param arraySupplier 提供一个数组
     * @param lengthFunc    获取数组的长度
     * @param putConsumer   自增方法
     * @param printConsumer 打印数组的方法
     * @param <T>
     */
    private static <T> void demo(
            Supplier<T> arraySupplier,
            Function<T, Integer> lengthFunc,
            BiConsumer<T, Integer> putConsumer,
            Consumer<T> printConsumer) {
        // 操作线程
        List<Thread> ts = new ArrayList<>();
        // 获取数组
        T array = arraySupplier.get();
        // 获取数组长度
        Integer length = lengthFunc.apply(array);
        for (int i = 0; i < length; i++) {
            // 对数组每个元素开启一个线程
            ts.add(new Thread(() -> {
                // 每个线程对数组中元素做+1操作(分散到每个元素上)
                for (int j = 0; j < 10000; j++) {
                    putConsumer.accept(array, j % length);
                }
            }));
        }
        // 启动线程
        ts.forEach(Thread::start);
        ts.forEach(t -> {
            try {
                t.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        // 所有线程操作完毕  打印
        // 如果数组是线程安全的 则 每个元素值为10000
        // 如果数组是不安全的 则每个元素值  不定
        printConsumer.accept(array);
    }

}
